home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.09 Sep 89 / MacApp Code / QPlot - McMath / UQPlot.inc1.p < prev    next >
Encoding:
Text File  |  1989-05-05  |  25.7 KB  |  939 lines  |  [TEXT/MPS ]

  1. {Copyright © 1988 by Charles F. McMath  All rights reserved.}
  2. CONST
  3.     kPlotWindowID    =    1001;
  4.     kPlotDLOG        =    2000;
  5.     kPlotID            =    'PPRM';
  6.     
  7.     kStaggerAmt        =    16;
  8.     
  9.     cGraphColor    =    1201;        { these are command numbers }
  10.     cAxisColor    =    1202;
  11.     cBackColor    =    1203;
  12.     
  13.     cGrafBlack    =    10001;
  14.     cGrafWhite    =    10002;
  15.     cGrafRed    =    10003;
  16.     cGrafGreen    =    10004;
  17.     cGrafBlue    =    10005;
  18.     cGrafCyan    =    10006;
  19.     cGrafMagenta=    10007;
  20.     cGrafYellow    =    10008;
  21.     
  22.     cAxisBlack    =    11001;
  23.     cAxisWhite    =    11002;
  24.     cAxisRed    =    11003;
  25.     cAxisGreen    =    11004;
  26.     cAxisBlue    =    11005;
  27.     cAxisCyan    =    11006;
  28.     cAxisMagenta=    11007;
  29.     cAxisYellow    =    11008;
  30.  
  31.     cBackBlack    =    12001;
  32.     cBackWhite    =    12002;
  33.     cBackRed    =    12003;
  34.     cBackGreen    =    12004;
  35.     cBackBlue    =    12005;
  36.     cBackCyan    =    12006;
  37.     cBackMagenta=    12007;
  38.     cBackYellow    =    12008;
  39.     
  40.     cPrintWS    =    1301;
  41.     cPrintPS    =    1302;
  42.     
  43. (*
  44.  *    The following constants relate to DLOG and ALRT numbers.
  45.  *)
  46.      kAboutDLOG    =    1024;        { our about box DLOG ID }
  47. VAR
  48.     gStaggerCount:    INTEGER;
  49.     colors:            ARRAY [1..8] OF INTEGER;
  50.     crString:        Str255;
  51.     
  52. {------------------------------------------------------------------------}
  53. FUNCTION Int2Str(theInt: INTEGER): Str255;
  54. (*
  55.  *    This utility function takes an integer and converts it into a
  56.  * string.
  57.  *)
  58. VAR
  59.     tempLong:        LongInt;
  60.     tempStr:        Str255;
  61. BEGIN
  62.     tempLong := theInt;
  63.     NumToString(tempLong, tempStr);
  64.     Int2Str := tempStr;
  65. END;        { Int2Str }
  66. {------------------------------------------------------------------------}
  67. FUNCTION Real2String(theReal: REAL; numDigits: INTEGER): Str255;
  68. (*
  69.  *    This function takes a real number, and converts it to a string with
  70.  * the specified number of digits PAST the decimal point.
  71.  *)
  72. VAR
  73.     theForm:    DecForm;
  74.     xTemp:        Extended;
  75.     tempStr:    DecStr;
  76. BEGIN
  77.     theForm.style := FixedDecimal;
  78.     theForm.digits := numDigits;
  79.     
  80.     xTemp := theReal;
  81.     Num2Str(theForm, xTemp, tempStr);
  82.     Real2String := tempStr;
  83. END;        { Real2String }
  84. {------------------------------------------------------------------------}
  85. FUNCTION String2Real(theString: Str255): REAL;
  86. (*
  87.  *    This function takes a string form of a real number, and converts
  88.  * it into the real number.
  89.  *)
  90. VAR
  91.     xTemp:    Extended;
  92. BEGIN
  93.     xTemp := Str2Num(theString);
  94.     String2Real := Num2Real(xTemp);
  95. END;        { String2Real }
  96. {------------------------------------------------------------------------}
  97. {------------------  QPlot Application Methods  -------------------------}
  98. {------------------------------------------------------------------------}
  99. PROCEDURE TQPlotApplication.IQPlotApplication(itsMainFileType: OSType);
  100. (*
  101.  *    This procedure initializes the application.  It sets up all of our
  102.  * global variables and fills the color index array.
  103.  *)
  104. VAR
  105.     aQPlotView:        TQPlotView;
  106. BEGIN
  107.     IApplication(itsMainFileType);
  108.     
  109.     crString[0] := CHR(1);
  110.     crString[1] := CHR(13);
  111.     
  112.     colors[1]     :=    33;        { black }
  113.     colors[2]    :=    30;        { white }
  114.     colors[3]    :=    205;    { red }
  115.     colors[4]    :=    341;    { green }
  116.     colors[5]    :=    409;    { blue }
  117.     colors[6]    :=    273;    { cyan }
  118.     colors[7]    :=    137;    { magenta }
  119.     colors[8]    :=    69;        { yellow }
  120.     
  121.     fDefGraph := colors[3];
  122.     fDefAxis := colors[1];
  123.     fDefBack := colors[2];
  124.     fPrintOpt := 1;
  125.     
  126.     gStaggerCount := 0;
  127. END;        { TQPlotApplication.IQPlotApplication }
  128. {------------------------------------------------------------------------}
  129. FUNCTION  TQPlotApplication.DoMakeDocument(itsCmdNumber: CmdNumber):
  130.         TDocument; OVERRIDE;
  131. (*
  132.  *    This function is called whenever we're creating a new document.  It
  133.  * creates the document object and returns it (properly initialized, of
  134.  * course).
  135.  *)
  136. VAR
  137.     aQPlotDocument:        TQPlotDocument;
  138. BEGIN
  139.     New(aQPlotDocument);
  140.     FailNil(aQPlotDocument);
  141.     aQPlotDocument.IQPlotDocument(kFileType, kSignature, kUsesDataFork,
  142.             NOT kUsesRsrcFork, NOT kDataOpen, NOT kRsrcOpen);
  143.  
  144.     aQPlotDocument.fSavePrintInfo := FALSE;
  145.     DoMakeDocument := aQPlotDocument;
  146. END;        { TQPlotApplication.DoMakeDocument }
  147. {------------------------------------------------------------------------}
  148. PROCEDURE TQPlotApplication.HandleFinderRequest; OVERRIDE;
  149. BEGIN
  150.     { just override this so we don't put up a blank document }
  151. END;        { TQPlotApplication.HandleFinderRequest }
  152. {------------------------------------------------------------------------}
  153. PROCEDURE TQPlotApplication.DoSetupMenus; OVERRIDE;
  154. (*
  155.  *    This procedure enables the appropriate menu items for the application.
  156.  *)
  157. BEGIN
  158.     INHERITED DoSetupMenus;
  159.     
  160.     Enable(cGraphColor, TRUE);
  161.     Enable(cAxisColor, TRUE);
  162.     Enable(cBackColor, TRUE);
  163. (*
  164.  *    Enable all of these, and put a check by the current one.
  165.  *)
  166.     EnableCheck(cGrafBlack, TRUE, fDefGraph=colors[1]);
  167.     EnableCheck(cGrafWhite, TRUE, fDefGraph=colors[2]);
  168.     EnableCheck(cGrafRed, TRUE, fDefGraph=colors[3]);
  169.     EnableCheck(cGrafGreen, TRUE, fDefGraph=colors[4]);
  170.     EnableCheck(cGrafBlue, TRUE, fDefGraph=colors[5]);
  171.     EnableCheck(cGrafCyan, TRUE, fDefGraph=colors[6]);
  172.     EnableCheck(cGrafMagenta, TRUE, fDefGraph=colors[7]);
  173.     EnableCheck(cGrafYellow, TRUE, fDefGraph=colors[8]);
  174.     
  175.     EnableCheck(cAxisBlack, TRUE, fDefAxis=colors[1]);
  176.     EnableCheck(cAxisWhite, TRUE, fDefAxis=colors[2]);
  177.     EnableCheck(cAxisRed, TRUE, fDefAxis=colors[3]);
  178.     EnableCheck(cAxisGreen, TRUE, fDefAxis=colors[4]);
  179.     EnableCheck(cAxisBlue, TRUE, fDefAxis=colors[5]);
  180.     EnableCheck(cAxisCyan, TRUE, fDefAxis=colors[6]);
  181.     EnableCheck(cAxisMagenta, TRUE, fDefAxis=colors[7]);
  182.     EnableCheck(cAxisYellow, TRUE, fDefAxis=colors[8]);
  183.     
  184.     EnableCheck(cBackBlack, TRUE, fDefBack=colors[1]);
  185.     EnableCheck(cBackWhite, TRUE, fDefBack=colors[2]);
  186.     EnableCheck(cBackRed, TRUE, fDefBack=colors[3]);
  187.     EnableCheck(cBackGreen, TRUE, fDefBack=colors[4]);
  188.     EnableCheck(cBackBlue, TRUE, fDefBack=colors[5]);
  189.     EnableCheck(cBackCyan, TRUE, fDefBack=colors[6]);
  190.     EnableCheck(cBackMagenta, TRUE, fDefBack=colors[7]);
  191.     EnableCheck(cBackYellow, TRUE, fDefBack=colors[8]);
  192.     
  193. END;        { TQPlotApplication.DoSetupMenus }
  194. {------------------------------------------------------------------------}
  195. FUNCTION TQPlotApplication.DoMenuCommand(aCmdNumber: CmdNumber): TCommand; OVERRIDE;
  196. (*
  197.  *    This function handles menu requests that pertain to the application.  It
  198.  * ensures that choices that change colors work correctly.
  199.  *)
  200. BEGIN
  201.     DoMenuCommand := gNoChanges;
  202.     CASE aCmdNumber OF
  203.     cAboutApp:
  204.         ShowAboutApp;
  205.     cGrafBlack,
  206.      cGrafWhite,
  207.      cGrafRed,
  208.      cGrafGreen,
  209.      cGrafBlue,
  210.      cGrafCyan,
  211.      cGrafMagenta,
  212.      cGrafYellow:
  213.          fDefGraph := colors[aCmdNumber - cGrafBlack + 1];
  214.     cAxisBlack,
  215.      cAxisWhite,
  216.      cAxisRed,
  217.      cAxisGreen,
  218.      cAxisBlue,
  219.      cAxisCyan,
  220.      cAxisMagenta,
  221.      cAxisYellow:
  222.          fDefAxis := colors[aCmdNumber - cAxisBlack + 1];
  223.     cBackBlack,
  224.      cBackWhite,
  225.      cBackRed,
  226.      cBackGreen,
  227.      cBackBlue,
  228.      cBackCyan,
  229.      cBackMagenta,
  230.      cBackYellow:
  231.          fDefBack := colors[aCmdNumber - cBackBlack + 1];
  232.     cPrintWS,
  233.      cPrintPS:
  234.          fPrintOpt := aCmdNumber - cPrintWS + 1;
  235.     OTHERWISE
  236.         DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  237.     END;        { case }
  238. END;        { TQPlotApplication.DoMenuCommand }
  239. {------------------------------------------------------------------------}
  240. PROCEDURE DrawBox(wPtr: WindowPtr; itemNum: INTEGER);
  241. (*
  242.  *    This procedure is the UserItem proc that gets called for the about box.
  243.  *)
  244. VAR
  245.     ityp:        INTEGER;
  246.     itemHdl:    Handle;
  247.     tRect:        Rect;
  248. BEGIN
  249.     GetDItem(DialogPtr(wPtr), 5, ityp, itemHdl, tRect);
  250.     FrameRect(tRect);
  251. END;        { DrawBox }
  252. {------------------------------------------------------------------------}
  253. PROCEDURE TQPlotApplication.ShowAboutApp;
  254. (*
  255.  *    Show our about box.  This version is almost identical to the original,
  256.  * except for the addition of some stuff about MacApp (incidentally, this
  257.  * is required by the license agreement for programs developed with MacApp!)
  258.  *)
  259. VAR
  260.     idStrHandle:        StringHandle;
  261.     freeSpace:            Size;
  262.     myHeapSpace:        LongInt;
  263.     tempStr1:            Str255;
  264.     tempStr2:            Str255;
  265.     tempStr3:            Str255;
  266.     diaPtr:                DialogPtr;
  267.     itemHit:            INTEGER;
  268.     
  269.     ityp:                INTEGER;
  270.     itemHdl:            Handle;
  271.     tRect:                Rect;
  272. BEGIN
  273.     idStrHandle := StringHandle(GetResource(kSignature, 0));
  274.     FailNIL(idStrHandle);
  275.  
  276.     MoveHHi(Handle(idStrHandle));
  277.     HLock(Handle(idStrHandle));
  278.     
  279.     freeSpace := FreeMem;
  280.     myHeapSpace := MaxMem(freeSpace);
  281.     NumToString(myHeapSpace, tempStr2);
  282.     tempStr2 := concat('Memory = ', tempStr2);
  283.     tempStr3 := '';
  284.     tempStr1 := '';
  285.     ParamText(idStrHandle^^, tempStr1, tempStr2, tempStr3);
  286.     diaPtr := GetNewDialog(kAboutDLOG, NIL, Pointer(-1));
  287.     FailNIL(diaPtr);
  288.     GetDItem(diaPtr, 5, ityp, itemHdl, tRect);
  289.     SetDItem(diaPtr, 5, ityp, Handle(@DrawBox), tRect);
  290.  
  291.     InitCursor;
  292.     ModalDialog(NIL, itemHit);
  293.     DisposDialog(diaPtr);
  294.  
  295.     HUnlock(Handle(idStrHandle));
  296. END;        { TQPlotApplication.ShowAboutApp }
  297. {------------------------------------------------------------------------}
  298. {-------------------  QPlot Document Methods  ---------------------------}
  299. {------------------------------------------------------------------------}
  300. PROCEDURE TQPlotDocument.IQPlotDocument(itsFileType, itsCreator: OSType;
  301.                                 usesDataFork, usesRsrcFork: BOOLEAN;
  302.                                 keepsDataOpen, keepsRsrcOpen: BOOLEAN);
  303. (*
  304.  *    Initialize the QPlot document.  For our document, this means that we
  305.  * will present the dialog box that asks for the quadratic parameters,
  306.  * and we'll solve the equation while we're here.
  307.  *)
  308. VAR
  309.     x1, x2:        REAL;
  310. BEGIN
  311.     IDocument(itsFileType, itsCreator, usesDataFork, usesRsrcFork,
  312.                         keepsDataOpen, keepsRsrcOpen);
  313.                         
  314.     PosePlotDialog;
  315.     fResult := SolveIt(fAParam, fBParam, fCParam, x1, x2);
  316.     IF (fResult<>-1) THEN
  317.         BEGIN
  318.         fRoot1 := x1;
  319.         fRoot2 := x2;
  320.         END
  321.     ELSE
  322.         BEGIN
  323.         fRoot1 := -999;
  324.         fRoot2 := -999
  325.     END;
  326.     fPlotView := NIL;
  327. END;        { TQPlotDocument.IQPlotDocument }
  328. {------------------------------------------------------------------------}
  329. PROCEDURE TQPlotDocument.DoMakeWindows; OVERRIDE;
  330. (*
  331.  *    This procedure is called when we have to make a new document (and its
  332.  * associated window).  We just get a simple window and shove it on the
  333.  * screen.
  334.  *)
  335. VAR
  336.     aWindow:    TWindow;
  337. BEGIN
  338.     aWindow := NewSimpleWindow(kPlotWindowID,
  339.                     kWantHScrollBar, kWantVScrollBar, 
  340.                     SELF, fPlotView);
  341.     aWindow.SimpleStagger(kStaggerAmt, kStaggerAmt, gStaggerCount);
  342. END;        { TQPlotDocument.DoMakeWindows }
  343. {------------------------------------------------------------------------}
  344. PROCEDURE TQPlotDocument.DoMakeViews(forPrinting: BOOLEAN); OVERRIDE;
  345. (*
  346.  *    This procedure is called when we are making a new document.  It creates
  347.  * all views that are needed.  In our case, it's only one.  We then initialize
  348.  * the view.
  349.  *)
  350. VAR
  351.     plotApp:        TQPlotApplication;
  352.     aQPlotView:        TQPlotView;
  353.     aHandler:        TStdPrintHandler;
  354.     tRect:            Rect;
  355. BEGIN
  356.     plotApp := TQPlotApplication(gApplication);
  357.     
  358.     NEW(aQPlotView);
  359.     FailNIL(aQPlotView);
  360.     aQPlotView.IQPlotView(SELF, plotApp.fDefGraph, plotApp.fDefAxis,
  361.                         plotApp.fDefBack);
  362.     
  363.     fPlotView := aQPlotView;
  364. (*
  365.  *    Now make the view printable by creating a print handler.
  366.  *)
  367.     IF NOT(forPrinting) THEN
  368.         BEGIN
  369.         New(aHandler);
  370.         FailNIL(aHandler);
  371.         aHandler.IStdPrintHandler(SELF, aQPlotView, FALSE, TRUE, TRUE);
  372.         SetRect(tRect,35,35,-35,-35);        { set up for 1/2" margins }
  373.         aHandler.InstallMargins(tRect, FALSE);
  374.     END;
  375. END;        { TQPlotDocument.DoMakeViews }
  376. {------------------------------------------------------------------------}
  377. PROCEDURE TQPlotDocument.PosePlotDialog;
  378. (*
  379.  *    This procedure puts up the dialog that requests the quadratic parameters.
  380.  *)
  381.  
  382.     FUNCTION CvtEditReal(aText: TEditText): Real;
  383.     VAR
  384.         tempStr:        Str255;
  385.     BEGIN
  386.         aText.GetText(tempStr);
  387.         CvtEditReal := String2Real(tempStr);
  388.     END;        { CvtEditReal }
  389.     
  390.     FUNCTION CvtEditInt(aText: TEditText): INTEGER;
  391.     VAR
  392.         tempStr:        Str255;
  393.         tempLong:        LongInt;
  394.     BEGIN
  395.         aText.GetText(tempStr);
  396.         StringToNum(tempStr, tempLong);
  397.         CvtEditInt := tempLong;
  398.     END;        { CvtEditInt }
  399. VAR
  400.     aWindow:    TWindow;
  401.     dismisser:    IDType;
  402.     
  403.     aQPlotView:    TQPlotView;
  404.     dView:        TDialogView;
  405.     anEditText:    TEditText;
  406.     aVal:        TEditText;
  407.     bVal:        TEditText;
  408.     cVal:        TEditText;
  409.     stepVal:    TEditText;
  410.     xVal:        TEditText;
  411.     yVal:        TEditText;
  412.     
  413.     tempStr:    Str255;
  414. BEGIN
  415. (*
  416.  *    First make our calls (which never get executed)
  417.  * to tell the linker we want to create these types of objects.
  418.  *)
  419.      IF gCreateWithTemplates THEN    
  420.         BEGIN    
  421.         NEW(aQPlotView);
  422.         NEW(dView);
  423.         NEW(anEditText);
  424.         END;
  425. (*
  426.  *    Get the dialog window and find the dialog subview.
  427.  *)
  428.      aWindow := NewTemplateWindow(kPlotDLOG, NIL);
  429.     dView := TDialogView(aWindow.FindSubView(kPlotID));
  430. (*
  431.  *    Retrieve references to each of the edit text items.  We
  432.  * will need to reference them later to get their values.
  433.  *)
  434.     aVal := TEditText(dView.FindSubView('a   '));
  435.     bVal := TEditText(dView.FindSubView('b   '));
  436.     cVal := TEditText(dView.FindSubView('c   '));
  437.     stepVal := TEditText(dView.FindSubView('step'));
  438.     xVal := TEditText(dView.FindSubView('xscl'));
  439.     yVal := TEditText(dView.FindSubView('yscl'));
  440.  
  441.     dView.SelectEditText('a   ', kRedraw);
  442.     
  443.     dismisser := dView.PoseModally;
  444. (*
  445.  *    Now that we have the values, convert them to numbers and plug them into
  446.  * the quadratic equation solver.  Note that we don't test to see if
  447.  * the OK button was pressed, because in this dialog, you can't exit
  448.  * except by saying OK.
  449.  *)
  450.     fAParam := CvtEditReal(aVal);
  451.     fBParam := CvtEditReal(bVal);
  452.     fCParam := CvtEditReal(cVal);
  453.     fStep := CvtEditReal(stepVal);
  454.     fXScale := CvtEditInt(xVal);
  455.     fYScale := CvtEditInt(yVal);
  456.  
  457.     aWindow.Close;
  458. END;        { TQPlotDocument.PosePlotDialog }
  459. {------------------------------------------------------------------------}
  460. PROCEDURE TQPlotDocument.Quad(a, b, c : REAL;VAR x1, x2 : REAL;
  461.                         VAR result : INTEGER);
  462. (*
  463.  *    This procedure is identical to the one written in 'vanilla' Pascal
  464.  *)
  465.     VAR
  466.         check : real;
  467.         
  468.     FUNCTION PositiveCalc (a, b, check : real) : real;
  469.     BEGIN
  470.         PositiveCalc := (-b + sqrt(check)) / (2 * a);
  471.     END;        { PositiveCalc ---------------------- }
  472.     
  473.     FUNCTION NegativeCalc (a, b, check : real) : real;
  474.     BEGIN
  475.         NegativeCalc := (-b - sqrt(check)) / (2 * a);
  476.     END;        { NegativeCalc ---------------------- }
  477.  
  478. BEGIN
  479.     result := 0;
  480.     check := (b * b) - (4 * a * c);
  481.     IF result = 0 THEN
  482.         BEGIN
  483.      { Check if double root exists }
  484.             IF check = 0 THEN
  485.                 BEGIN
  486.                     result := 2;
  487.                     x1 := positivecalc(a, b, check);
  488.                     x2 := x1;
  489.                 END;
  490.     { Check if real result}
  491.             IF check > 0 THEN
  492.                 BEGIN
  493.                     result := 1;
  494.                     x1 := positivecalc(a, b, check);
  495.                     x2 := negativecalc(a, b, check);
  496.                 END;
  497.     { Check if root is complex }
  498.             IF check < 0 THEN
  499.                 BEGIN
  500.                     result := 3;
  501.                     check := -check;
  502.                     x1 := positivecalc(a, b, check);
  503.                     x2 := negativecalc(a, b, check);
  504.                 END;
  505.         END;
  506. END;        { TQPlotDocument.Quad }
  507. {------------------------------------------------------------------------}
  508. FUNCTION TQPlotDocument.SolveIt(a, b, c: REAL; VAR x1, x2: REAL): INTEGER;
  509. (*
  510.  *    This function is identical to the one written for the original program.
  511.  *)
  512. VAR
  513.     result:    INTEGER;
  514. BEGIN
  515.     IF (a <> 0) THEN
  516.         quad(a, b, c, x1, x2, result)
  517.     ELSE
  518.         result := -1;
  519.     SolveIt := result;
  520. END;        { TQPlotDocument.SolveIt }
  521. {------------------------------------------------------------------------}
  522. PROCEDURE TQPlotDocument.DoNeedDiskSpace(VAR dataForkBytes,
  523.                             rsrcForkBytes: LONGINT); OVERRIDE;
  524. (*
  525.  *    This procedure calculates the amount of disk space we need to store
  526.  * our document on disk.  In our case, it's just the size of the drawing
  527.  * since no additional information is stored in our file.
  528.  *)
  529. BEGIN
  530.     INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
  531.     
  532.     dataForkBytes := dataForkBytes + 512 { header } +
  533.                         GetHandleSize(Handle(fPlotView.fDrawing));
  534. END;        { TQPlotDocument.DoNeedDiskSpace }
  535. {------------------------------------------------------------------------}
  536. PROCEDURE TQPlotDocument.DoWrite(aRefNum: INTEGER; makingCopy: BOOLEAN); OVERRIDE;
  537. (*
  538.  *    This procedure is called to write the data onto the disk.
  539.  *)
  540. VAR
  541.     count:        LongInt;
  542.     buffer:        ARRAY [1..256] OF INTEGER;
  543.     pHdl:        PicHandle;
  544.     i:            INTEGER;
  545.     err:        OSErr;
  546. BEGIN
  547.     INHERITED DoWrite(aRefNum, makingCopy);        { create file, etc }
  548. (*
  549.  *    Now write the blank 512 byte header needed for PICT files.
  550.  *)
  551.      FOR i:= 1 TO 256 DO
  552.         buffer[i] := 0;
  553.         
  554.      count := 512;
  555.     err := FSWrite(aRefNum, count, @buffer);
  556.     IF ((err<>noErr) OR (count<>512)) THEN
  557.         SysBeep(10);        { @@@ error alert }
  558.     
  559.     pHdl := fPlotView.fDrawing;
  560.     HLock(Handle(pHdl));
  561.     count := GetHandleSize(Handle(pHdl));
  562.     err := FSWrite(aRefNum, count, Ptr(pHdl^));
  563.     HUnlock(Handle(pHdl));
  564.     IF ((err<>noErr) OR (count <> GetHandleSize(Handle(pHdl)))) THEN
  565.         SysBeep(10);        { @@@ error alert }
  566. END;        { TQPlotDocument.DoWrite }
  567. {------------------------------------------------------------------------}
  568. {---------------------  QPlot View Methods  -----------------------------}
  569. {------------------------------------------------------------------------}
  570. PROCEDURE TQPlotView.IQPlotView(theDoc: TQPlotDocument; theGrafColor,
  571.                     theAxisColor, theBackColor: INTEGER);
  572. (*
  573.  *    This procedure is called to initialize a QPlot view.  It sets the
  574.  * view's variables to good initial values.
  575.  *)
  576. VAR
  577.     vOrigin:    VPoint;
  578.     vSize:        VPoint;
  579.     tempPort:    GrafPtr;
  580. BEGIN
  581.     SetVPt(vOrigin, 0, 0);
  582.     SetVPt(vSize, 600, 400);
  583.  
  584.     IView(theDoc, NIL, vOrigin, vSize, sizeVariable, sizeVariable);
  585.     fPlotDoc := theDoc;
  586.  
  587.     fDrawing := NIL;
  588.     fOnePage := FALSE;
  589.     END;        { TQPlotView.IQPlotView }
  590. {------------------------------------------------------------------------}
  591. PROCEDURE TQPlotView.Free; OVERRIDE;
  592. (*
  593.  *    This procedure is called when the view is finished, and we are cleaning
  594.  * up any space we have allocated.  We just dispose of the picture handle.
  595.  *)
  596. BEGIN
  597.     KillPicture(fDrawing);
  598.     INHERITED Free;
  599. END;        { TQPlotView.Free }
  600. {------------------------------------------------------------------------}
  601. PROCEDURE TQPlotView.CalcMinSize(VAR minSize: VPoint); OVERRIDE;
  602. (*
  603.  *    This procedure is called to calculate the minimum size of the view.
  604.  * It is called initially when the view is being created, and later on
  605.  * when we tell the view to recalculate its view size.
  606.  *)
  607. VAR
  608.     vSize:        Point;
  609.     tWind:        TWindow;
  610.     tRect:        Rect;
  611. BEGIN
  612.     INHERITED CalcMinSize(minSize);
  613.     IF fOnePage THEN
  614.         BEGIN
  615.         minSize := fPrintHandler.fViewPerPage;
  616.         END
  617.     ELSE
  618.         BEGIN
  619.         IF (fSuperView<>NIL) THEN
  620.             minSize := fSuperView.fSize
  621.         ELSE
  622.             BEGIN
  623.             vSize := Point(0);
  624.             IF SELF.Focus THEN 
  625.                 Writeln('focus worked!');
  626.             QDToViewPt(vSize, minSize);
  627.         END;
  628.     END;
  629. END;        { TQPlotView.CalcMinSize }
  630. {------------------------------------------------------------------------}
  631. PROCEDURE TQPlotView.DoSetupMenus; OVERRIDE;
  632. (*
  633.  *    This procedure is called to enable menu items that pertain to
  634.  * the view.
  635.  *)
  636. BEGIN
  637.     INHERITED DoSetupMenus;
  638.  
  639.     EnableCheck(cPrintWS, TRUE, NOT fOnePage);
  640.     EnableCheck(cPrintPS, TRUE, fOnePage);
  641. END;        { TQPlotView.DoSetupMenus }
  642. {------------------------------------------------------------------------}
  643. FUNCTION TQPlotView.DoMenuCommand(aCmdNumber: CmdNumber): TCommand; OVERRIDE;
  644. (*
  645.  *    This function is called to handle menu commands that pertain to
  646.  * the view.
  647.  *)
  648. VAR
  649.     tempVPt:    VPoint;
  650.     tRect:        Rect;
  651. BEGIN
  652.     DoMenuCommand := gNoChanges;
  653.     IF (aCmdNumber = cPrintWS) OR (aCmdNumber = cPrintPS) THEN
  654.         BEGIN
  655.         fOnePage := (aCmdNumber=cPrintPS);
  656.         AdjustSize;
  657.         END
  658.     ELSE
  659.         DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  660. END;        { TQPlotView.DoMenuCommand }
  661. {------------------------------------------------------------------------}
  662. PROCEDURE TQPlotView.PrQDStuff(pRect : rect; QDdevice : integer);
  663. (*
  664.  *    This is the main drawing procedure for the view.  It is (almost) unchanged
  665.  * from the original version.  Since in MacApp you don't know who you're 
  666.  * drawing for (Display vs. LaserWriter) most of the display-specific code has
  667.  * been deleted.  Drawing still works correctly, since we erase the invalid
  668.  * areas before we draw it.
  669.  *)
  670. CONST
  671.     Display = 1;
  672.     LaserWriter = 2;
  673.     ImageWriter = 3;
  674.     
  675.     NoJust = 0;
  676.     LeftJust = 1;
  677.     CenterJust = 2;
  678.     RightJust = 3;
  679.     FullJust = 4;
  680.     LinesInParagraph = 5;
  681. {selected MacDraw comments}
  682.     picDwgBeg = 130;
  683.     picDwgEnd = 131;
  684.     picGrpBeg = 140;
  685.     picGrpEnd = 141;
  686.     TextBegin = 150;
  687.     TextEnd = 151;
  688.     StringBegin = 151;
  689.     StringEnd = 153;
  690.     TextCenter = 154;
  691. {postscript comments}
  692.     SetLineWidth = 182;
  693.     PostScriptBegin = 190;
  694.     TextIsPostscript = 194;
  695.     PostScriptEnd = 191;
  696. TYPE
  697.     widhdl = ^widptr;
  698.     widptr = ^widpt;
  699.     widpt = Point;
  700.  
  701.     TTxtPicRec = PACKED RECORD
  702.             tJus : Byte;
  703.             tFlip : Byte;
  704.             tRot : Integer;
  705.             tLine : Byte;
  706.             tCmnt : Byte;
  707.         END;
  708.  
  709. VAR
  710.     le, tp, ri, bo : integer;
  711.     str1, str2, str3, str4, str5 : str255;
  712.     str6, str7, str8, str9 : str255;
  713.     hPos, vPos, hor, ver : integer;
  714.     x, y, z1, z2 : real;
  715.     rBox, ClipBox : rect;
  716.     Width : Widhdl;
  717.     leading : integer;
  718.     LineNo : integer;
  719.     ParagraphBegin : Point;
  720.     Indent : integer;
  721.     Paragraph : ARRAY[1..LinesInParagraph] OF str255;
  722.     TxtPicRec : TTxtPicRec;
  723.     TxtPicPtr : QDPtr;
  724.     TxtPicHdl : QDHandle;
  725.     TextClipRgn : RgnHandle;
  726.     SaveClip : RgnHandle;
  727.     fInfo : FontInfo;
  728.  
  729. BEGIN
  730.     SaveClip := NewRgn;
  731.     GetClip(SaveClip);
  732.     ClipRect(pRect);
  733.     TextClipRgn := NewRgn;
  734.     
  735.     penNormal;
  736.     
  737.     TextFont(geneva);
  738.     TextSize(10);
  739.     TextFace([]);
  740.     
  741.     hor := (pRect.right - pRect.left) DIV 2;
  742.     ver := (pRect.bottom - pRect.top) DIV 2;
  743.     Width := Widhdl(NewHandle(sizeof(widpt)));
  744.     Width^^.h := 10;
  745.     Width^^.v := 1;
  746.     TxtPicPtr := @TxtPicRec;
  747.     TxtPicHdl := @TxtPicPtr;
  748.     TxtPicRec.tJus := LeftJust;
  749.     TxtPicRec.tFlip := 0; {no flip}
  750.     TxtPicRec.tRot := 0; {no rotation}
  751.     TxtPicRec.tLine := 2; {1 1/2 spacing}
  752.     GetFontInfo(fInfo);
  753.     leading := fInfo.descent + fInfo.ascent + fInfo.leading;
  754.     Indent := 2;
  755.     WITH fPlotDoc DO
  756.         BEGIN
  757.         x := -fXScale / 2;
  758.         y := fAParam * x * x + (fBParam * x) + fCParam;
  759.         hPos := INTEGER(ROUND(x * hor * 2 / fXScale + hor));
  760.         vPos := INTEGER(round(-y * ver * 2 / fYScale + ver));
  761.         z1 := -fBParam / (2 * fAParam);
  762.         z2 := (4 * fAParam * fCParam - (fBParam * fBParam)) / (4 * fAParam);
  763.     END;
  764.     le := 2;
  765.     tp := ver + (ver DIV 3);
  766.     ri := 140;
  767.     IF ri >= (hor + hor DIV 3) THEN
  768.         ri := hor + hor DIV 3;
  769.     bo := ver + ver - 2;
  770.     setRect(rBox, le, tp - 14, ri, bo);
  771.     ParagraphBegin.h := 4;
  772.     ParagraphBegin.v := tp;
  773.  
  774. {Graph Text}
  775.     WITH fPlotDoc DO
  776.         BEGIN
  777.         str1 := Int2Str(-fXScale DIV 2);
  778.         str2 := Int2Str(fYScale DIV 2);
  779.         str3 := Int2Str(fXScale DIV 2);
  780.         str4 := Int2Str(-fYScale DIV 2);
  781.     
  782.         Paragraph[1] := CONCAT('y=ax^2 + bx + c', crString);
  783.         Paragraph[2] := CONCAT('a=', Real2String(fAParam,1), ', b=', Real2String(fBParam,1), ', c=', Real2String(fCParam,1), crString);
  784.         Paragraph[3] := CONCAT('x1=', Real2String(fRoot1,2), ', x2=', Real2String(fRoot2,2), crString);
  785.     END;
  786.     
  787.     CASE fPlotDoc.fResult OF
  788.         1 : 
  789.             Paragraph[4] := CONCAT('Two Real Roots, x1, x2', crString);
  790.         2 : 
  791.             Paragraph[4] := CONCAT('Double Root', crString);
  792.         3 : 
  793.             Paragraph[4] := CONCAT('Two Complex Roots ', crString);
  794.         OTHERWISE
  795.             ;
  796.     END;
  797.     Paragraph[5] := CONCAT('Slope 0 = (', Real2String(z1, 1), ',',Real2String(z2,1), ')', crString);
  798.  
  799.     PenNormal;
  800.     BackColor(TQPlotApplication(gApplication).fDefBack);
  801.     ForeColor(TQPlotApplication(gApplication).fDefAxis);
  802.  
  803. {Drawing Boundry}
  804.     PicComment(picDwgBeg, 0, NIL); {Begin MacDraw Document}
  805.     PicComment(picGrpBeg, 0, NIL);
  806.     PicComment(SetLineWidth, GetHandleSize(Handle(Width)), Handle(Width));
  807.  
  808.     IF QDdevice = Display THEN
  809.         FillRect(pRect, white);
  810.     FrameRect(pRect);
  811.     
  812.  
  813. {Two Axis}
  814.     PicComment(picGrpBeg, 0, NIL);
  815.     moveto(0, ver);
  816.     line(hor + hor, 0);
  817.     moveto(hor, 0);
  818.     line(0, ver + ver);
  819.     PicComment(picGrpEnd, 0, NIL);
  820.  
  821.     ForeColor(TQPlotApplication(gApplication).fDefGraph);
  822.  
  823. {Plot Itsef}
  824.     PicComment(picGrpBeg, 0, NIL);
  825.     moveto(hPos, vPos);
  826.     WITH fPlotDoc DO
  827.         REPEAT
  828.             x := x + fStep;
  829.             y := fAParam * x * x + (fBParam * x) + fCParam;
  830.             hPos := integer(round(x * hor * 2 / fXScale + hor));
  831.             vPos := integer(round(-y * ver * 2 / fYScale + ver));
  832.             WITH pRect DO
  833.                 IF (hPos < right) AND (hPos > left) AND (vPos < bottom) AND (vPos > top) THEN
  834.                     LineTo(hPos, vPos)
  835.                 ELSE
  836.                     moveto(hPos, vPos);
  837.         UNTIL x >= fXScale / 2;
  838.     PicComment(picGrpEnd, 0, NIL);
  839.  
  840.     ForeColor(Colors[1]);
  841.  
  842. {Axis Text}
  843.     moveto(4, ver + 14);
  844.     DrawString(str1);
  845.     moveto(hor - 40, 14);
  846.     DrawString(str2);
  847.     moveto(hor + hor - 50, ver + 14);
  848.     DrawString(str3);
  849.     moveto(hor - 40, ver + ver - 14);
  850.     DrawString(str4);
  851.  
  852. {Box }
  853.     PicComment(picGrpBeg, 0, NIL);
  854.     PicComment(picGrpBeg, 0, NIL);
  855.  
  856.     PicComment(SetLineWidth, GetHandleSize(Handle(Width)), Handle(Width));
  857.  
  858.     IF QDdevice = Display THEN
  859.         fillRect(rBox, white);
  860.     frameRect(rBox);
  861.     PicComment(picGrpEnd, 0, NIL); {of box}
  862.  
  863.     GetClip(TextClipRgn);
  864.     ClipBox := rBox;
  865.     ClipRect(ClipBox);
  866.  
  867. {Box Text}
  868.     PicComment(TextBegin, sizeof(TTxtPicRec), Handle(TxtPicHdl));
  869.     FOR LineNo := 1 TO LinesInParagraph DO
  870.         BEGIN
  871.             moveto(ParagraphBegin.h, ParagraphBegin.v);
  872.             move(Indent, (LineNo - 1) * leading);
  873.             DrawString(Paragraph[LineNo]);
  874.         END;
  875.     PicComment(TextEnd, 0, NIL);
  876.     PicComment(PicGrpEnd, 0, NIL); {of Box & text}
  877.     PicComment(PicGrpEnd, 0, NIL); {of select all objects}
  878.     picComment(picDwgEnd, 0, NIL); {of drawing}
  879.  
  880.     SetClip(SaveClip);
  881.     disposHandle(handle(width));
  882.     DisposeRgn(TextClipRgn);
  883.     DisposeRgn(SaveClip);
  884. END;        { TQPlotView.PrQDStuff }
  885. {------------------------------------------------------------------------}
  886. PROCEDURE TQPlotView.SuperViewChangedSize (delta: VPoint;
  887.                 invalidate: BOOLEAN); OVERRIDE;
  888. (*
  889.  *    This procedure changes the view size when the window is resized.
  890.  *)
  891. BEGIN
  892. (*
  893.  *    We only need to go through these shenanigans if we are NOT
  894.  * displaying a page-sized picture.  This resizes the view's extent
  895.  * rectangle and invalidates the area, forcing the view to redraw
  896.  * the picture in the new size.
  897.  *)
  898.     IF NOT(fOnePage) THEN
  899.         BEGIN
  900.         AdjustSize;
  901.         ForceRedraw;
  902.     END;
  903. END;        { TQPlotView.SuperViewChangedSize }
  904. {------------------------------------------------------------------------}
  905. PROCEDURE TQPlotView.Resize (width, height: VCoordinate;
  906.                 invalidate: BOOLEAN); OVERRIDE;
  907. (*
  908.  *    This procedure is called from AdjustSize.  It is here because when
  909.  * we toggle between Page Size and Window Size plots, we need to 
  910.  * tell the view to redraw itself (because it changed size, even though
  911.  * the window didn't).
  912.  *)
  913. BEGIN
  914.     ForceRedraw;
  915.     INHERITED Resize(width, height, FALSE);
  916.     ForceRedraw;
  917. END;        { TQPlotView.Resize }
  918. {------------------------------------------------------------------------}
  919. PROCEDURE TQPlotView.Draw(area: Rect); OVERRIDE;
  920. (*
  921.  *    This procedure is called to draw the view when it needs to be drawn.
  922.  * The picture we created before is ALWAYS drawn to take up the entire window.
  923.  *)
  924. VAR
  925.     tRect:        Rect;
  926. BEGIN
  927.  
  928.     GetQDExtent(tRect);        { always draw pict to fill entire extent of the view }
  929.     EraseRect(tRect);
  930.     IF (fDrawing=NIL) THEN
  931.         BEGIN
  932.         fDrawing := OpenPicture(tRect);
  933.         PrQDStuff(tRect, 1);
  934.         ClosePicture;
  935.         PenNormal;
  936.     END;
  937.     DrawPicture(fDrawing, tRect);
  938. END;        { TQPlotView.Draw }
  939.